package com.phs.main.security.shiro;

import com.phs.main.security.jwt.JWTFilter;
import com.phs.main.security.shiro.realms.LoginRealm;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

	/**
	 * 拦截所有请求
	 *
	 * @param securityManager 安全管理器
	 * @return 过滤器链
	 */
	@Bean("shiroFilter")
	public ShiroFilterFactoryBean factoryBean(@Qualifier("securityManager1") DefaultWebSecurityManager securityManager) {
		ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

		// 设置filter 安全管理器
		factoryBean.setSecurityManager(securityManager);

		// 认证和授权，权限设置
		Map<String, String> map = new HashMap<>();

		/*
		  /index.html = anon
		  /user/create = authc
		  /user/** = authcBasic
		  /admin/** = authc, roles[administrator]
		  /admin/** = authc, roles["administrator,guest"]
		  /rest/** = authc, rest
		  /rest/ajax/** = authc, perms[rest:ajax]
		  /rest/ajax/** = authc, perms["rest:ajax:*,user:add"]
		  /rest/aj?x/** = port[8081]

		  /r*t = prems[user:method]   (method: post, delete, get 等)

		  ?  匹配一个字符
		  *  匹配一个或多个字符
		  ** 匹配一个或多个目录


		  	anon				可以匿名使用
		  	authc				需要认证（登录）
		  	authcBasic			需要通过 httpBasic 验证
		  	logout				登出
		  	noSessionCreation	阻止请求期间创建会话
		  	prems[]				满足全部权限列表
		  	port				指定可访问的端口
		  	rest				根据请求的方法 （没啥用？）
		  	roles[]				满足角色列表
		  	ssl					https
		  	user				必须存在用户

		 */

		// swagger
		map.put("/swagger-ui.html", "anon");
		map.put("/swagger-resources/**", "anon");
		map.put("/v2/**", "anon");
		map.put("/webjars/**", "anon");
		// druid
		map.put("/druid/**", "roles[admin]");
		// 不受限的放上面
		map.put("/sysUsers/login*", "anon");
//		map.put("/**", "authc");

		// 添加自定义过滤器并且取名为jwt
		Map<String, Filter> filterMap = new HashMap<>(1);
		filterMap.put("jwt", new JWTFilter());
		factoryBean.setFilters(filterMap);

		// 所有请求通过jwt
		map.put("/**", "jwt");

		factoryBean.setFilterChainDefinitionMap(map);
		//	跳转登录页面，不改则为login.jsp
		factoryBean.setLoginUrl("/sys/common/403");
		//无权限
		factoryBean.setUnauthorizedUrl("/sys/common/403");

		return factoryBean;
	}

	/**
	 * 安全管理器
	 *
	 * @param loginRealm 自定义realm
	 * @return 安全管理器
	 */
	@Bean("securityManager1")
	public DefaultWebSecurityManager securityManager1(@Qualifier("loginRealm") LoginRealm loginRealm) {
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		manager.setRealm(loginRealm);

		//关闭自带session，http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
		DefaultSessionStorageEvaluator evaluator = new DefaultSessionStorageEvaluator();
		evaluator.setSessionStorageEnabled(false);

		DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
		subjectDAO.setSessionStorageEvaluator(evaluator);

		manager.setSubjectDAO(subjectDAO);

		return manager;
	}


	@Bean
	@DependsOn("lifecycleBeanPostProcessor")
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		// 强制使用cglib，防止重复代理和可能引起代理出错的问题
		// https://zhuanlan.zhihu.com/p/29161098
		defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
		return defaultAdvisorAutoProxyCreator;
	}

	@Bean
	public LoginRealm loginRealm() {
		LoginRealm realm = new LoginRealm();

//		//	开启缓存管理
//		realm.setCacheManager(new RedisCacheManager());
//		//	开启全局缓存
//		realm.setCachingEnabled(true);
//		//	认证缓存
//		realm.setAuthenticationCachingEnabled(true);
//		realm.setAuthenticationCacheName("authenticationCache");
//		//	授权缓存
//		realm.setAuthorizationCachingEnabled(true);
//		realm.setAuthorizationCacheName("authorizationCache");

		return realm;
	}

	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		advisor.setSecurityManager(securityManager);
		return advisor;
	}

}
